/**
 * Copyright(c) 2014 Xunton Solutions
 *
 * History:
 *   14-12-23 下午2:46 Created by dwzhang
 */
package com.jade.bss.beacon.impl;

import java.util.List;

import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import com.jade.bss.base.customer.Customer;
import com.jade.bss.beacon.*;
import com.jade.framework.base.criterion.Criteria;
import com.jade.framework.base.criterion.sql.SqlUtils;
import com.jade.framework.base.util.PagingList;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;

/**
 * 采用JPA方式的数据访问接口。
 *
 * @author <a href="mailto:dwzhang@xunton.com">dwzhang</a> 
 * @version 1.0 14-12-23 下午2:46
 */
@Named ("bss_beaconDao")
public class JpaBeaconDao
        implements BeaconDao
{
    @PersistenceContext (unitName = "default")
    protected EntityManager entityManager;

    @Caching (evict = {@CacheEvict (value = "bss.beacon.q", allEntries = true),
            @CacheEvict (value = "bss.beacon.l", allEntries = true)})
    public void addBeacon(Beacon beacon)
            throws BeaconException
    {
        entityManager.persist(beacon);
    }

    @Caching (evict = {@CacheEvict (value = "bss.beacon.q", allEntries = true),
            @CacheEvict (value = "bss.beacon.l", allEntries = true),
            @CacheEvict (value = "bss.beacon.gumm", allEntries = true),
            @CacheEvict (value = "bss.beacon.gm", allEntries = true),
            @CacheEvict (value = "bss.beacon.g", key="#beacon.id")})
    public void updateBeacon(Beacon beacon)
            throws BeaconException
    {
        entityManager.merge(beacon);
    }

    @Caching (evict = {@CacheEvict (value = "bss.beacon.q", allEntries = true),
            @CacheEvict (value = "bss.beacon.l", allEntries = true),
            @CacheEvict (value = "bss.beacon.gumm", allEntries = true),
            @CacheEvict (value = "bss.beacon.gm", allEntries = true),
            @CacheEvict (value = "bss.beacon.g", allEntries = true)})
    public void removeBeacon(long id)
            throws BeaconException
    {
        Beacon beacon = getBeacon(id);
        if (beacon != null) {
            entityManager.remove(beacon);
        }
    }



    @Caching (evict = {@CacheEvict (value = "bss.beacon.q", allEntries = true),
            @CacheEvict (value = "bss.beacon.l", allEntries = true),
            @CacheEvict (value = "bss.beacon.gumm", allEntries = true),
            @CacheEvict (value = "bss.beacon.gm", allEntries = true),
            @CacheEvict (value = "bss.beacon.g", key = "#id")})
    public int updateStatus(long id, int status)
            throws BeaconException
    {
        String sql = "UPDATE Beacon SET status=:status WHERE id=:id";
        Query query = entityManager.createQuery(sql);
        query.setParameter("id", id);
        query.setParameter("status", status);
        return query.executeUpdate();
    }

    @Cacheable (value = "bss.beacon.gumm", key = "#uuid+'_'+#major+'_'+#minor")
    public Beacon getBeacon(String uuid,int major,int minor){
        String sql = "SELECT beacon from Beacon beacon WHERE proximityUUID=:uuid and major=:major and minor=:minor";
        Query query = entityManager.createQuery(sql);
        query.setParameter("uuid",uuid);
        query.setParameter("major",major);
        query.setParameter("minor",minor);
        return SqlUtils.getSingleResult(query);
    }

    @Cacheable (value = "bss.beacon.gm", key = "#mac")
    public Beacon getBeaconByMac(String mac){
        String sql = "SELECT beacon from Beacon beacon WHERE macAddress=:mac";
        Query query = entityManager.createQuery(sql);
        query.setParameter("mac",mac);
        return SqlUtils.getSingleResult(query);
    }

    @Cacheable (value = "bss.beacon.g", key = "#id")
    public Beacon getBeacon(long id)
    {
        return entityManager.find(Beacon.class, id);
    }



    @Cacheable (value = "bss.beacon.l", key = "#criteria")
    public List<Beacon> listBeacon(Criteria criteria)
    {
        String sql = "Select beacon FROM Beacon beacon";
        return SqlUtils.sqlQueryWithoutCount(sql, entityManager, criteria);
    }

    @Cacheable (value = "bss.beacon.q", key = "#criteria")
    public PagingList<Beacon> queryBeacon(Criteria criteria)
    {
        String sql = "Select beacon FROM Beacon beacon";
        return SqlUtils.sqlQuery(sql, entityManager, criteria);
    }

    @Cacheable (value = "bss.beacon.q", condition = "#root.args.length > 1", key = "#criteria + '_' + #infos")
    public PagingList<Beacon> queryBeacon(Criteria criteria, Class... infos)
    {
        return doQueryBeacon(criteria, infos);
    }


    public void addBeaconEvent(BeaconEventRecord record)
            throws BeaconException
    {
        entityManager.persist(record);
    }


    @Cacheable (value = "bss.beacon.info.g", key = "#beaconId + '_' + #infoClass.name")
    public <Info extends BeaconExtInfo> Info getInfo(long beaconId, Class infoClass)
    {
        return (Info) entityManager.find(infoClass, beaconId);
    }

    @Caching (
            evict = {@CacheEvict (value = "bss.beacon.info.g", key = "#info.beaconId + '_' + #info.getClass().name")})
    public void addInfo(BeaconExtInfo info)
            throws BeaconException
    {
        entityManager.persist(info);
    }

    @Caching (
            evict = {@CacheEvict (value = "bss.beacon.info.g", key = "#info.beaconId + '_' + #info.getClass().name")})
    public void updateInfo(BeaconExtInfo info)
            throws BeaconException
    {
        entityManager.merge(info);
    }

    @Caching (
            evict = {@CacheEvict (value = "bss.beacon.info.g", key = "#info.beaconId + '_' + #info.getClass().name")})
    public void removeInfo(BeaconExtInfo info)
            throws BeaconException
    {
        BeaconExtInfo bi = entityManager.find(info.getClass(), info.getBeaconId());
        if (bi != null) {
            entityManager.remove(bi);
        }
    }



    public long getBeaconCount(Criteria criteria)
    {
        String sql = "SELECT COUNT(entity) FROM Beacon entity";
        List<Object> list = SqlUtils.sqlQueryWithoutCount(sql,entityManager,criteria);
        if(list!=null&&list.size()>0)
            return (Long)list.get(0);
        else
            return 0;
    }

    protected String[] getInfoCondition(Class... infos)
    {
        String[] condition = new String[]{"", ""};
        if (infos != null && infos.length > 0) {
            for (Class info : infos) {
                String className = info.getSimpleName();
                String name = className.substring(0, 1).toLowerCase() + className.substring(1);
                condition[0] += "," + className + " " + name;
                condition[1] += " AND beacon.id=" + name + ".beaconId";
            }
        }
        return condition;
    }

    protected PagingList<Beacon> doQueryBeacon(Criteria criteria, Class... infos)
    {
        String sql = "SELECT beacon FROM Beacon beacon";
        String[] array = getInfoCondition(infos);
        sql += array[0];
        if (StringUtils.isNotEmpty(array[1])) {
            sql += " WHERE " + array[1].substring(4);
        }
        return SqlUtils.sqlQuery(sql, entityManager, criteria);
    }
}
